/** bolaserver.c - Servidor do jogo **/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "bola.h"
#include "bolaserver.h"

static game_room *gr[MAXROOMS];

/**
 * Inicializa o servidor
 */
void init_server()
{
    int i;

    for (i = 0; i < MAXROOMS; i++)
    {
        gr[i] = NULL;
    }
}

/**
 * Adiciona um jogador. Essa função cria um arquivo que tem o
 * nome igual ao nome do jogador. Retorna -1 se ocorreu um erro.
 */
int *addplayer_1_svc(player * p, struct svc_req *rqstp)
{
    static int result;

    FILE *pfile;

    pfile = fopen(p->name, "w+");
    if (pfile == NULL)
    {
        result = -1;
        return &result;
    }

    fprintf(pfile, "%s\n", p->name);
    fprintf(pfile, "%d\n", p->score);

    fclose(pfile);

    result = 0;
    return &result;
}

/**
 * Remove um jogador. Remove o arquivo que possui um nome igual ao nome do
 * jogador. Retorna -1 se ocorreu um erro.
 */
int *rmplayer_1_svc(player * p, struct svc_req *rqstp)
{
    static int result;

    result = unlink(p->name);

    return &result;
}

/**
 * Cria uma sala. Retorna -1 se não tiver espaço para criar a sala, caso
 * contrário retorna o número da sala criada.
 */
int *createroom_1_svc(room * r, struct svc_req *rqstp)
{
    static int result;

    int i = 0;

    for (i = 0; gr[i] != NULL && i < MAXROOMS; i++);

    if (i == MAXROOMS)
    {
        result = -1;
        return &result;
    }

    gr[i] = malloc(sizeof(game_room));
    strcpy(gr[i]->name, r->name);
    gr[i]->p1 = r->p;
    gr[i]->s.shot_number = 0;
    gr[i]->s.first = NULL;
    gr[i]->status = WAITING;

    result = i;
    return &result;
}

/**
 * Remove uma sala. Retorna -1 se a sala não existir.
 */
int *rmroom_1_svc(int *a, struct svc_req *rqstp)
{
    static int result;

    /* se a sala não existe */
    if (gr[*a] == NULL)
    {
        result = -1;
        return &result;
    }

    /* remove a sala */
    free(gr[*a]);
    gr[*a] = NULL;

    result = 0;
    return &result;
}

/**
 * Entra na sala. Retorna -1 se a sala não existir ou se estiver 
 * ocorrendo um jogo nela.
 */
int *joinroom_1_svc(room * jr, struct svc_req *rqstp)
{
    static int result;

    /* se a sala não existe ou se está ocorrendo um jogo nela */
    if (gr[jr->room_id] == NULL || gr[jr->room_id]->status == PLAYING)
    {
        result = -1;
        return &result;
    }

    /* entra na sala */
    gr[jr->room_id]->status = PLAYING;
    gr[jr->room_id]->p2 = jr->p;

    result = 0;
    return &result;
}

/**
 * Realiza uma tacada. Retorna o número da tacada ou -1 se a sala não existe.
 */
int *makeshot_1_svc(shot * sht, struct svc_req *rqstp)
{
    static int result;

    int i;

    shot_sequence *aux = gr[sht->room_id]->s.first;

    if (gr[sht->room_id] == NULL)
    {
        result = -1;
        return &result;
    }

    gr[sht->room_id]->s.shot_number++;

    /* esta é a primeira tacada */
    if (gr[sht->room_id]->s.shot_number == 1)
    {
        gr[sht->room_id]->s.first = malloc(sizeof(shot_sequence));
        gr[sht->room_id]->s.first->s = (*sht);
        gr[sht->room_id]->s.first->next = NULL;
        result = 1;
        return &result;
    }

    /* procura um espaço vazio */
    while (aux->next != NULL)
    {
        aux = aux->next;
    }
    aux->next = malloc(sizeof(shot_sequence));
    aux->next->s = (*sht);
    aux->next->next = NULL;
    result = gr[sht->room_id]->s.shot_number;
    return &result;
}

/**
 * Espera a tacada ser realizada. Essa função compara a tacada atual com
 * a passada por parâmetro. Retorna 0 se a tacada ainda não foi realizada, 
 * caso contrário retorna 1.
 */
int *waitshot_1_svc(shot * last_shot, struct svc_req *rqstp)
{
    static int result;

    if (gr[last_shot->room_id] == NULL)
    {
        result = -1;
    }
    else if (last_shot->shot_num < gr[last_shot->room_id]->s.shot_number)
    {
        result = 1;
    }
    else
    {
        result = 0;
    }

    return &result;
}

/**
 * Retorna a força da última tacada.
 */
float *waitshotforce_1_svc(int *room_id, struct svc_req *rqstp)
{
    static float result;

    shot_sequence *aux = gr[*room_id]->s.first;

    while (aux->next != NULL)
        aux = aux->next;

    result = aux->s.force;

    return &result;
}

/**
 * Retorna o ângulo da última tacada.
 */
float *waitshotangle_1_svc(int *room_id, struct svc_req *rqstp)
{

    static float result;

    shot_sequence *aux = gr[*room_id]->s.first;

    while (aux->next != NULL)
        aux = aux->next;

    result = aux->s.angle;

    return &result;
}
